/*
 ===============================================================================
 Name        : main.c
 Author      : 
 Version     :
 Copyright   : Copyright (C)
 Description : main definition
 ===============================================================================
 */

#include "LPC13xx.h"
#include <cr_section_macros.h>
#include <NXP/crp.h>

#include "usb.h"
#include "usbdesc.h"
#include "msccallback.h"
#include "diskimg.h"
#include "rom_drivers.h"
#include "iap.h"

// Variable to store CRP value in. Will be placed automatically
// by the linker when "Enable Code Read Protect" selected.
// See crp.h header for more information
__CRP const unsigned int CRP_WORD = CRP_NO_CRP;

USB_DEV_INFO DeviceInfo;
MSC_DEVICE_INFO MscDevInfo;
ROM ** rom = (ROM **) 0x1fff1ff8;

void execute_user_code(void) {
	void (*user_code_entry)(void);

	unsigned *p; // used for loading address of reset handler from user flash

	/* Change the Vector Table to the USER_FLASH_START
	 in case the user application uses interrupts */

	SCB->VTOR = (USER_FLASH_START & 0x1FFFFF80);

	// Load contents of second word of user flash - the reset handler address
	// in the applications vector table
	p = (unsigned *) (USER_FLASH_START + 4);

	// Set user_code_entry to be the address contained in that second word
	// of user flash
	user_code_entry = (void *) *p;

	// Jump to user application
	user_code_entry();

}

void check_isp_entry(void) {
	if (LPC_PMU->GPREG0 != 0x5a5a5a5a) {
		LPC_PMU->GPREG0 = 0;
		execute_user_code();
	} else {
		// Enter ISP mode
	}
}

void enter_usb_isp() {
	volatile uint32_t n;

	user_flash_erased = 0;

	//kopiowanie hasła
	for (pi = 0; pi < sizeof(pass_start); pi++)
		pass[pi] = pass_start[pi];

	// Generate File Allocation Table to save Flash space
	// First Two FAT entries are reserved
	Fat_RootDir[0] = 0xF8;
	Fat_RootDir[1] = 0xFF;
	Fat_RootDir[2] = 0xFF;

	// Copy root directory entries
	for (n = 0; n < 12; n++) { // Copy Initial Disk Image
		Fat_RootDir[(FAT_SIZE + n)] = RootDirEntry[n]; //   from Flash to RAM
	}

	MscDevInfo.idVendor = 0x1FC9;
	MscDevInfo.idProduct = 0x0501;
	MscDevInfo.bcdDevice = 0x0101;
	MscDevInfo.StrDescPtr = (uint32_t) &USB_StringDescriptor[0];
	MscDevInfo.MSCInquiryStr = (uint32_t) &InquiryStr[0];
	MscDevInfo.BlockSize = MSC_BlockSize;
	MscDevInfo.BlockCount = MSC_BlockCount;
	MscDevInfo.MemorySize = MSC_MemorySize;
	MscDevInfo.MSC_Read = MSC_MemoryRead;
	MscDevInfo.MSC_Write = MSC_MemoryWrite;

	DeviceInfo.DevType = USB_DEVICE_CLASS_STORAGE;
	DeviceInfo.DevDetailPtr = (uint32_t) &MscDevInfo;

#define     EN_TIMER32_1    (1<<10)
#define     EN_IOCON        (1<<16)
#define     EN_USBREG       (1<<14)

	LPC_SYSCON->SYSAHBCLKCTRL |= (EN_TIMER32_1 | EN_IOCON | EN_USBREG);

	(*rom)->pUSBD->init_clk_pins(); /* Use pll and pin init function in rom */

	/* insert a delay between clk init and usb init */
	for (n = 0; n < 75; n++) {
	}

	(*rom)->pUSBD->init(&DeviceInfo); /* USB Initialization */
	init_msdstate(); /* Initialize Storage state machine */

	(*rom)->pUSBD->connect(1); /* USB Connect */

	while (1)
		__WFI(); /* Loop forever */
}

void USB_IRQHandler(void) {
	(*rom)->pUSBD->isr();
}

int main(void) {

	if (user_code_present()) {
		check_isp_entry();
	}

	enter_usb_isp();

	while (1)
		;
	return 0;
}

